package com.kaifamiao.annotation;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.logging.Logger;

// 首先标注 @Component 以便于组件扫描时能扫描到该组件
@Component
// 然后再标注 @Aspect 以便于声明该组件是个切面组件
@Aspect
@Order(7)
public class TigerAspect {

    private static Logger logger = Logger.getGlobal();

    @Pointcut("execution(* com.kaifamiao.annotation.TigerService.*(..))")
    private void pc(){
        // 通过为 私有的、无参的、返回类型是 void 的方法标注 @Pointcut 注解的方式来定义切点
    }

    @Before("pc()")
    public void before(JoinPoint p) { // 当前方法本身就是个 advice
        logger.info( p.getSignature().getName() + "即将执行" );
    }

    @Around("pc()")
    public Object around( ProceedingJoinPoint jp ) throws Throwable {
        String name = jp.getSignature().getName(); // 获得目标方法名称
        logger.info( "开始为[" + name + "]方法计时");
        long begin = System.nanoTime();
        Object result = jp.proceed(); // 通过连接点调用目标方法
        long end = System.nanoTime();
        logger.info( "方法[" + name + "]执行耗时" + ( end - begin ) + "ns." );
        return result;
    }

    @AfterReturning( pointcut = "pc()", returning = "rv" )
    public void afterReturn( JoinPoint jp, Object rv ) {
        String name = jp.getSignature().getName(); // 获得目标方法名称
        logger.info( "方法["+ name + "]返回: " + rv );
    }

    @AfterThrowing( pointcut = "pc()", throwing = "th" )
    public void afterThrow( JoinPoint jp, Throwable th ) {
        String name = jp.getSignature().getName(); // 获得目标方法名称
        logger.info( "方法["+ name + "]抛出: " + th.getClass().getName() );
    }

    @After("pc()")
    public void after(JoinPoint p){
        logger.info( p.getSignature().getName() + "执行结束" );
    }

}
